﻿using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using ZYLFramework.Common;

namespace ZYLFramework.Manage
{

    /// <summary>实例化继承引用接口。</summary>
    public interface IReference
    {
        /// <summary>清理引用。</summary>
        void Clear();
    }

    /// <summary>
    /// 对象池类
    /// </summary>
    public class ClassObjectPool<T> where T:IReference,new()
    {
        protected Stack<T> pool = new Stack<T>();
        //最大对象个数  <=0表示不限制个数
        //没有回收的个数
        protected int noRecycleCount;
        public ClassObjectPool(int maxCount)
        {
            for (int i = 0; i < maxCount; i++)
            {
                pool.Push(new T());
            }
        }

        /// <summary>
        /// 从池里面取类对象
        /// </summary>
        public T Spawn()
        {
            if (pool.Count == 0)
            {
                pool.Push(new T());
                noRecycleCount++;
            }
            T rtn = pool.Pop();
            return rtn;
        }

        /// <summary>
        /// 回收类对象
        /// </summary>
        public bool Recycle(T obj)
        {
            if (obj == null)
                return false;
            noRecycleCount--;
            obj.Clear();
            pool.Push(obj);
            return true;
        }
    }


    /// <summary>
    /// 对象池管理类
    /// </summary>
    public class ObjectPoolManager : MonoSingleton<ObjectPoolManager>
    {
        protected Dictionary<Type, object> classObjectPoolDic = new Dictionary<Type, object>();

        private static int _defaultPoolMaxNum = 10;
        /// <summary>
        /// 创建类对象池，创建完成后在外面可以保存ClassObjectPool<T>，然后调用Spawn和Recycle来创建和回收类对象
        /// </summary>
        public ClassObjectPool<T> GetOrCreateClassObjectPool<T>(int maxCount)where T:IReference,new()
        {
            Type type = typeof(T);
            object obj = null;
            if(!classObjectPoolDic.TryGetValue(type,out obj) || obj==null)
            {
                ClassObjectPool<T> newPool = new ClassObjectPool<T>(maxCount);
                classObjectPoolDic.Add(type, newPool);
                return newPool;
            }
            return obj as ClassObjectPool<T>;
        }

        public T GetObject<T>()where T:IReference,new()
        {
            var tempPool = GetOrCreateClassObjectPool<T>(_defaultPoolMaxNum);
            return tempPool.Spawn();
        }
        
        public bool Recycle<T>(T obj)where T:IReference,new()
        {
            var tempPool = GetOrCreateClassObjectPool<T>(_defaultPoolMaxNum);
            return tempPool.Recycle(obj);
        }

        //延迟回收
        IEnumerator DelayRecycle<T>(float delayTime,T obj) where T : IReference, new()
        {
            yield return new WaitForSeconds(delayTime);
            Recycle(obj);//回收物体
        }
    }
}